﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using SST.WebClient.Data;
using SST.WebClient.Util;
using System.IO;
using System.Text.RegularExpressions;
using System.Collections.Generic;

namespace SST.WebClient
{
    /// <summary>
    /// Provide request queue information
    /// Contains parser logic to convert html to information object
    /// </summary>
    public class RequestQueueInfo
    {
        public event EventHandler<RequestQueueInfoGetAsyncEventArgs> GetAsyncCompleted;

        /// <summary>
        /// Get current request information
        /// </summary>
        /// <returns></returns>
        public void GetAsync()
        {
            Helper helper = new Helper();
            helper.DownloadWebpageAsyncCompleted += (s, e) =>
            {
                //begin parsing
                Soundtrack track = new Soundtrack();
                List<StreamingRequest> requestList = new List<StreamingRequest>();
                
                try
                {
                    using (StringReader reader = new StringReader(e.Html))
                    {
                        bool isMarkerReached = false;
                        //fast forward to table header
                        do
                        {
                            string tmp = reader.ReadLine();
                            if (tmp == null)
                                break;
                            if (tmp.ToUpper().Contains("ALBUM"))
                            {
                                isMarkerReached = true;
                                break;
                            }
                        } while (reader.Peek() != -1);
                        if (!isMarkerReached)
                            throw new Exception("table header not found");
                        Helper.Debug("table header located, proceed to request list");

                        //loop till end
                        //record last number, to ignore passed request
                        int previousRequestNum = 0;
                        do
                        {
                            //locate request number
                            int currentRequestNum = 0;

                            Match requestM = Helper.ForwardMatch(reader, new Regex("<b>" //start of <b> tag
                                + "([0-9]+)"    //numbers
                                + "</b>"        //end </b>
                                , RegexOptions.Compiled));

                            if (requestM != null && requestM.Groups.Count == 2)
                            {
                                currentRequestNum = int.Parse(requestM.Groups[1].Value);
                                Helper.Debug("currentRequestNum=" + currentRequestNum.ToString());
                            }

                            //if current request smaller than previous, means the request list has already passed
                            if (currentRequestNum < previousRequestNum)
                            {
                                Helper.Debug("request list ended");
                                break;
                            }

                            StreamingRequest request = new StreamingRequest()
                            {
                                Track = new Soundtrack()
                            };
                            
                            Match m = null;
                            #region Track duration
                            m = Helper.ForwardMatch(reader, new Regex(
                                "("             // start group 1
                                + "[0-9]+"      // number (minutes of track duration)
                                + ":"           // colon (separator of minutes and seconds)
                                + "[0-9]+"      // number (seconds of track duration)
                                + ")"           // end group 1
                                , RegexOptions.Compiled));

                            if (m != null && m.Groups.Count == 2)
                            {
                                string[] durationArray = m.Groups[1].Value.Split(':');
                                if (durationArray.Length != 2)
                                    Helper.Debug("Invalid duration format " + m.Groups[1].Value);
                                else
                                    request.Track.Duration = int.Parse(durationArray[0]) * 60 + int.Parse(durationArray[1]);
                                Helper.Debug("request.Track.Duration=" + request.Track.Duration);
                            }
                            else
                                Helper.Debug("duration not found");
                            #endregion

                            #region Album Url
                            m = Helper.ForwardMatch(reader, new Regex(
                                "<a href=\""        // start of <a>
                                + "../../"          // the paths characters
                                + "("               // start group 1
                                + "[^\"]+"          // characters except double quote
                                + ")"               // end group 1
                                + "\""              // end with double quote
                                , RegexOptions.Compiled));

                            if (m != null && m.Groups.Count == 2)
                            {
                                request.Track.AlbumUrl = Common.SST_URL + "/" + m.Groups[1].Value;
                                Helper.Debug("request.Track.AlbumUrl=" + request.Track.AlbumUrl);
                            }
                            #endregion

                            #region Album art url
                            m = Helper.ForwardMatch(reader, new Regex(
                                "<img border=\"0\" src=\""  // start <img>
                                + "../../"                  // the paths characters
                                + "("                       // start group 1
                                + "[^\"]+"                  // characters except double quote
                                + ")"                       // end group 1
                                + "\""                      // end with double quote
                                , RegexOptions.Compiled));

                            if (m != null && m.Groups.Count == 2)
                            {
                                request.Track.AlbumArt = Common.SST_URL + "/" + m.Groups[1].Value;
                                Helper.Debug("request.Track.AlbumArt=" + request.Track.AlbumArt);
                            }
                            #endregion

                            #region Album name
                            m = Helper.ForwardMatch(reader, new Regex(
                                "<b>&nbsp;"     // start <b> and &nbsp;
                                + "("           // start group 1
                                + "[^<]+"       // characters except <
                                + ")"           // end group 1
                                + "</b>"        // end with double quote
                                , RegexOptions.Compiled));

                            if (m != null && m.Groups.Count == 2)
                            {
                                request.Track.Album = m.Groups[1].Value;
                                Helper.Debug("request.Track.Album=" + request.Track.Album);
                            }
                            #endregion

                            #region Title
                            m = Helper.ForwardMatch(reader, new Regex(
                                "&nbsp;"        // start &nbsp;
                                + "("           // start group 1
                                + "[^<]+"       // characters except <
                                + ")"           // end group 1
                                + ".+"          // any character
                                + "</td>"       // end with </td>
                                , RegexOptions.Compiled));

                            if (m != null && m.Groups.Count == 2)
                            {
                                request.Track.Title = m.Groups[1].Value;
                                Helper.Debug("request.Track.Title=" + request.Track.Title);
                            }
                            #endregion

                            #region requester
                            //skip two lines
                            reader.ReadLine();
                            reader.ReadLine();
                            //detect vip and non vip, because vip will have comment in second line
                            string tmp = reader.ReadLine();
                            if (tmp == null)
                            {
                                Helper.Debug("unexpected end when parsing requester");
                                break;
                            }
                            //detect system admin
                            if (tmp.Contains("<b>&nbsp;</b><i>System/Admin</i>"))
                            {
                                request.Requester = "System/Admin";
                                request.IsRequestByAdmin = true;
                            }
                            else
                            {
                                m = new Regex(
                                    "<b>&nbsp;"     // start <b>&nbsp;
                                    + "("           // start group 1
                                    + "[^<]+"       // characters except <
                                    + ")"           // end group 1
                                    + "[ \t]+"      // tab or space
                                    + "$"           // end of line
                                    , RegexOptions.Compiled).Match(tmp);

                                if (m.Success && m.Groups.Count == 2)
                                {
                                    //vip logic
                                    request.Requester = m.Groups[1].Value.Trim();

                                    //parse comment in second line
                                    tmp = reader.ReadLine();
                                    if (tmp == null)
                                    {
                                        Helper.Debug("unexpected end when parsing requester");
                                        break;
                                    }
                                    m = new Regex(
                                        "<br>&nbsp;"    // start with <br>&nbsp;
                                        + "("           // start group 1 (requester)
                                        + "[^<]+"       // characters except <
                                        + ")"           // end group 1
                                        , RegexOptions.Compiled).Match(tmp);

                                    if (m.Success && m.Groups.Count == 2)
                                        request.Comment = m.Groups[1].Value.Trim();
                                }
                                else
                                {
                                    //non vip logic, everything is in this line already, just need another parser
                                    m = new Regex(
                                        "<b>&nbsp;"            // start with <b>&nbsp;
                                        + "("                   // start group 1 (requester)
                                        + "[^<]+"               // characters except <
                                        + ")"                   // end group 1
                                        + "[ \t]*"              // space and tab character
                                        + "</b><br>&nbsp;"      // things between requester and comment
                                        + "("                   // start group 2 (comment)
                                        + "[^<]*"               // characters except <, but optional match
                                        + ")"                   // end group 2
                                        , RegexOptions.Compiled).Match(tmp);

                                    if (m.Success && m.Groups.Count == 3)
                                    {
                                        request.Requester = m.Groups[1].Value.Trim();
                                        request.Comment = m.Groups[2].Value.Trim();
                                    }
                                }
                                //set to null if empty string
                                if (request.Requester != null && request.Requester.Length == 0)
                                    request.Requester = null;
                                if (request.Comment != null && request.Comment.Length == 0)
                                    request.Comment = null;
                            }
                            Helper.Debug("Requester=" + request.Requester);
                            Helper.Debug("Comment=" + request.Comment);
                            #endregion

                            previousRequestNum = currentRequestNum;
                            requestList.Add(request);
                        } while (reader.Peek() != -1);
                    }
                }
                catch (Exception ex)
                {
                    Helper.Debug(ex);
                }
                OnGetAsyncCompleted(new RequestQueueInfoGetAsyncEventArgs(requestList));
            };
            helper.DownloadWebpageAsync("http://www.streamingsoundtracks.com/modules/Queue_Played/Queue_Played-gen.php?rand=" + DateTime.Now.Ticks);
        }

        // Wrap event invocations inside a protected virtual method
        // to allow derived classes to override the event invocation behavior
        protected virtual void OnGetAsyncCompleted(RequestQueueInfoGetAsyncEventArgs e)
        {
            // Make a temporary copy of the event to avoid possibility of
            // a race condition if the last subscriber unsubscribes
            // immediately after the null check and before the event is raised.
            EventHandler<RequestQueueInfoGetAsyncEventArgs> handler = GetAsyncCompleted;

            // Event will be null if there are no subscribers
            if (handler != null)
            {
                // Use the () operator to raise the event.
                System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => { handler(this, e); });
            }
        }
    }

    /// <summary>
    /// Contains current streaming request
    /// </summary>
    public class RequestQueueInfoGetAsyncEventArgs : EventArgs
    {
        private List<StreamingRequest> _requestList;

        public List<StreamingRequest> RequestList
        {
            get { return _requestList; }
            set { _requestList = value; }
        }

        public RequestQueueInfoGetAsyncEventArgs(List<StreamingRequest> request)
        {
            this._requestList = request;
        }
    }
}
